Advanced Jasmine Techniques

Web Development - জ্যাসমিনজেএস (JasmineJS)
468

JasmineJS একটি শক্তিশালী এবং জনপ্রিয় JavaScript টেস্টিং ফ্রেমওয়ার্ক, যা বিশেষ করে Behavior-Driven Development (BDD) অনুসরণ করে। এর মাধ্যমে আপনি সহজেই টেস্ট কেস লিখতে পারেন এবং সিস্টেমের আচরণ পরীক্ষা করতে পারেন। তবে, কিছু উন্নত (Advanced) টেকনিক ব্যবহার করলে JasmineJS এর পূর্ণ ক্ষমতা আরও বেশি কাজে লাগানো যায়।

এখানে কিছু উন্নত Jasmine টেকনিক আলোচনা করা হলো, যা আপনাকে আরও কার্যকরী, স্কেলেবল এবং সিস্টেমিক টেস্টিং পদ্ধতি তৈরি করতে সহায়তা করবে।


স্পাই এবং স্টাব (Spies and Stubs) ব্যবহার

JasmineJS এ spyOn() এবং spy ফিচারগুলি অত্যন্ত শক্তিশালী টেস্টিং টুল। এগুলোর মাধ্যমে আপনি কোডের নির্দিষ্ট অংশকে মক (mock) বা স্পাই (spy) করতে পারেন, যাতে অপ্রয়োজনীয় ডিপেনডেন্সির উপর নির্ভর না করে টেস্ট করা যায়।

Spy ব্যবহার

spyOn() ফাংশন ব্যবহার করে আপনি একটি ফাংশনের কার্যকারিতা পরীক্ষা করতে পারেন, যেমন কল হয়েছে কিনা বা কিভাবে কাজ করছে।

describe("Math Operations", function() {
  it("should call add method with correct arguments", function() {
    const mathOps = new MathOperations();
    spyOn(mathOps, 'add'); // add() মেথডটিকে স্পাই করা হচ্ছে
    mathOps.add(2, 3);
    expect(mathOps.add).toHaveBeenCalledWith(2, 3); // চেক করা হচ্ছে যে add() মেথডটি সঠিক আর্গুমেন্ট নিয়ে কল হয়েছে কি না
  });
});

Stub ব্যবহার

স্টাব (Stub) এর মাধ্যমে আপনি কোনো মেথডের বাস্তব কার্যকারিতা প্রতিস্থাপন করে নির্দিষ্ট ফলাফল ফিরিয়ে দিতে পারেন। JasmineJS তে and.returnValue() এবং and.callFake() স্টাবিং টেকনিক ব্যবহৃত হয়।

describe("API Service", function() {
  it("should return mock data for getUser method", function() {
    const apiService = new ApiService();
    spyOn(apiService, 'getUser').and.returnValue({ id: 1, name: "John" });
    
    const user = apiService.getUser();
    expect(user.name).toBe("John");
  });
});

এখানে, getUser মেথডটি মক করা হয়েছে এবং তার পরিবর্তে একটি কাস্টম রিটার্ন ভ্যালু প্রদান করা হয়েছে।


অ্যাসিঙ্ক্রোনাস টেস্টিং (Asynchronous Testing)

JasmineJS অ্যাসিঙ্ক্রোনাস কোডের জন্যও সমর্থন প্রদান করে। আপনি অ্যাসিঙ্ক্রোনাস কার্যক্রমের জন্য done() কলব্যাক ব্যবহার করতে পারেন।

Promise সহ অ্যাসিঙ্ক্রোনাস টেস্ট

describe("Asynchronous test with Promise", function() {
  it("should fetch data from API", function(done) {
    fetchDataFromApi().then(function(data) {
      expect(data).toEqual({ id: 1, name: "John" });
      done(); // done() কল করে অ্যাসিঙ্ক্রোনাস টেস্ট শেষ করা হয়
    });
  });
});

এখানে, fetchDataFromApi() একটি Promise রিটার্ন করছে, এবং done() ফাংশনটি নিশ্চিত করে যে টেস্টটি তখনই পাস হবে যখন Promise সম্পূর্ণ হবে।

Async/Await সহ অ্যাসিঙ্ক্রোনাস টেস্ট

JasmineJS ES6 এর async/await সাপোর্টও দেয়, যা অ্যাসিঙ্ক্রোনাস কোড লেখা আরও সহজ করে।

describe("Asynchronous test with async/await", function() {
  it("should fetch user data", async function() {
    const data = await fetchDataFromApi();
    expect(data).toEqual({ id: 1, name: "John" });
  });
});

এখানে async এবং await ব্যবহার করা হয়েছে অ্যাসিঙ্ক্রোনাস ফাংশনকে সিঙ্ক্রোনাস হিসেবে পরিচালনা করার জন্য।


টেস্ট ডাবল (Test Doubles)

JasmineJS এ টেস্ট ডাবল ব্যবহারের মাধ্যমে, আপনি মক, স্টাব, স্পাই ইত্যাদি তৈরি করতে পারেন যা মূল কার্যকলাপের প্রতিস্থাপন হিসেবে কাজ করে।

Fake Timer (Fake Time) ব্যবহার

আপনি fake timers ব্যবহার করে টাইম-ডিপেন্ডেন্ট টেস্ট গুলোর কার্যকারিতা সহজে টেস্ট করতে পারেন, যেমন setTimeout(), setInterval() ইত্যাদি।

describe("Fake Timers", function() {
  it("should call the callback after timeout", function() {
    jasmine.clock().install(); // Fake timer ইনস্টল
    const callback = jasmine.createSpy("callback");

    setTimeout(function() {
      callback();
    }, 1000);

    jasmine.clock().tick(1000); // 1000 মিলিসেকেন্ড পাস করা হচ্ছে
    expect(callback).toHaveBeenCalled();
    jasmine.clock().uninstall(); // Fake timer আনইনস্টল
  });
});

এখানে, jasmine.clock() ব্যবহার করে টেস্টে সময়ের কাজ পরীক্ষা করা হয়েছে, যা আসল সময়ের পরিবর্তে ফেক টাইমার ব্যবহার করে টেস্টের সময় নিয়ন্ত্রণ করতে সাহায্য করে।


টেস্টের পারফরম্যান্স অপটিমাইজেশন

কিছু ক্ষেত্রে, JasmineJS এ একাধিক টেস্ট একত্রিত করার ফলে পারফরম্যান্স সমস্যার সৃষ্টি হতে পারে। এই ধরনের পরিস্থিতিতে আপনি beforeAll(), afterAll() এবং beforeEach(), afterEach() ফাংশন ব্যবহার করে টেস্টের পরিবেশ প্রস্তুত ও সাফ করতে পারেন।

beforeAll() এবং afterAll()

beforeAll() এবং afterAll() ব্লকগুলি আপনার টেস্ট স্যুটের আগে এবং পরে একবার করে কার্যকর হয়, তাই এগুলি বড় আকারের প্রস্তুতিমূলক কাজের জন্য উপযুক্ত।

describe("Database Tests", function() {
  beforeAll(function() {
    // ডাটাবেস কানেকশন তৈরি
  });

  afterAll(function() {
    // ডাটাবেস কানেকশন বন্ধ
  });

  it("should return data", function() {
    expect(getData()).toBeDefined();
  });
});

beforeEach() এবং afterEach()

beforeEach() এবং afterEach() ব্লকগুলি প্রতিটি টেস্টের আগে এবং পরে চলবে, যাতে আপনি টেস্টের নির্ভরতা সঠিকভাবে ম্যানেজ করতে পারেন।

describe("Math Operations", function() {
  let calc;

  beforeEach(function() {
    calc = new Calculator();
  });

  afterEach(function() {
    // টেস্ট শেষে অবস্থা ক্লিন আপ
  });

  it("should add numbers correctly", function() {
    expect(calc.add(2, 3)).toBe(5);
  });
});

এখানে, beforeEach() ব্যবহার করে প্রতিটি টেস্টের জন্য নতুন Calculator অবজেক্ট তৈরি করা হয়েছে।


সারাংশ

JasmineJS এর মাধ্যমে উন্নত টেস্টিং কৌশলগুলি যেমন spy, stub, asynchronous testing, fake timers, এবং test doubles ব্যবহার করে আপনি আরও কার্যকরী, সুসংগঠিত এবং স্কেলেবল টেস্ট কেস তৈরি করতে পারেন। এই টেকনিকগুলি ব্যবহারের মাধ্যমে আপনার টেস্টিং প্রক্রিয়া আরো শক্তিশালী এবং নির্ভরযোগ্য হবে, যা সফটওয়্যারের গুণমান উন্নত করতে সাহায্য করবে।

Content added By

Dynamic Test Generation

203

Dynamic Test Generation একটি শক্তিশালী কৌশল, যার মাধ্যমে আপনি একই ধরনের টেস্টের ভিন্ন ভিন্ন কেস তৈরি করতে পারেন। JasmineJS এ Dynamic Test Generation ব্যবহার করে, আপনি টেস্ট কেসগুলোকে প্রোগ্রাম্যাটিকভাবে তৈরি করতে পারেন, যাতে পুনঃব্যবহারযোগ্য এবং স্কেলেবল টেস্ট কেস সৃষ্টি করা যায়। এটি সাধারণত forEach(), map(), বা it.each() (Jest এর মত) ফাংশনের মাধ্যমে সম্ভব হয়।

এই পদ্ধতির মাধ্যমে, আপনি একাধিক ইনপুটের জন্য একই ধরনের টেস্ট রচনা করতে পারেন, যা বিশেষত যখন একাধিক সেট ইনপুটের জন্য একই ধরনের টেস্ট করা প্রয়োজন হয় তখন খুবই কার্যকরী।


Dynamic Test Generation এর সুবিধা

  1. পুনঃব্যবহারযোগ্যতা: একই ধরনের টেস্ট একাধিক ইনপুট বা কন্ডিশনের জন্য লেখা হয়, যা কোডের পুনঃব্যবহারযোগ্যতা বৃদ্ধি করে।
  2. স্কেলেবিলিটি: অনেকগুলো ইনপুটের জন্য পৃথক পৃথক টেস্ট কেস না লিখে, একটি কেসের মাধ্যমে একাধিক ভ্যালিডেশন করা যায়।
  3. অটোমেশন: ডায়নামিক টেস্ট গেনারেশন অটোমেটিক টেস্টের জন্য খুবই কার্যকরী, বিশেষ করে বড় প্রকল্পে যেখানে বিভিন্ন ধরনের ইনপুটের জন্য টেস্ট প্রয়োজন হয়।

JasmineJS এ Dynamic Test Generation

JasmineJS এ ডায়নামিক টেস্ট তৈরি করতে forEach() বা Array মেথড ব্যবহার করা যেতে পারে। এতে আপনি একটি ইনপুট অ্যারে বা ডেটার উপর ভিত্তি করে একাধিক it() ব্লক তৈরি করতে পারেন।

Dynamic Test Generation এর উদাহরণ

ধরা যাক, আমাদের একটি ফাংশন আছে যা কোনো একটি নামের মধ্যে একটি নির্দিষ্ট শব্দটি খুঁজে বের করে। আমরা চাই একই ধরনের টেস্ট কেসগুলো বিভিন্ন নামের জন্য তৈরি করতে।

describe("Search functionality", function() {
  const testCases = [
    { name: "John Doe", searchTerm: "John", expected: true },
    { name: "Jane Doe", searchTerm: "John", expected: false },
    { name: "Mark Smith", searchTerm: "Smith", expected: true },
    { name: "Sara Lee", searchTerm: "Lee", expected: true }
  ];

  testCases.forEach(function(testCase) {
    it(`should return ${testCase.expected} when searching for "${testCase.searchTerm}" in "${testCase.name}"`, function() {
      const result = search(testCase.name, testCase.searchTerm);
      expect(result).toBe(testCase.expected);
    });
  });
});

এখানে:

  • testCases: একটি অ্যারে, যেখানে বিভিন্ন নাম এবং তাদের সাথে সংশ্লিষ্ট অনুসন্ধান শর্ত (যেমন searchTerm) এবং প্রত্যাশিত ফলাফল (যেমন expected) সংরক্ষিত রয়েছে।
  • forEach(): প্রতিটি testCase এর জন্য আলাদা আলাদা it() টেস্ট তৈরি করা হচ্ছে।

এটি আপনাকে একই ফাংশনের জন্য বিভিন্ন ইনপুট ও ফলাফলের জন্য একাধিক টেস্ট একযোগে চালাতে সহায়তা করবে।


আরও একটি উদাহরণ: বিভিন্ন ধরণের ইনপুট নিয়ে টেস্ট তৈরি করা

ধরা যাক, আমরা একটি ফাংশন তৈরি করেছি যা ক্যালকুলেটর হিসেবে কাজ করে এবং ভিন্ন ভিন্ন অপারেশন (যেমন যোগ, বিয়োগ, গুণ, ভাগ) গ্রহণ করে। আমরা চাই এই অপারেশনগুলো সবগুলোর জন্য ডায়নামিক টেস্ট তৈরি করতে।

describe("Calculator operations", function() {
  const operations = [
    { a: 5, b: 3, op: '+', expected: 8 },
    { a: 7, b: 2, op: '-', expected: 5 },
    { a: 4, b: 6, op: '*', expected: 24 },
    { a: 9, b: 3, op: '/', expected: 3 }
  ];

  operations.forEach(function(testCase) {
    it(`should calculate ${testCase.a} ${testCase.op} ${testCase.b} correctly`, function() {
      let result;
      switch (testCase.op) {
        case '+':
          result = testCase.a + testCase.b;
          break;
        case '-':
          result = testCase.a - testCase.b;
          break;
        case '*':
          result = testCase.a * testCase.b;
          break;
        case '/':
          result = testCase.a / testCase.b;
          break;
      }
      expect(result).toBe(testCase.expected);
    });
  });
});

এখানে:

  • operations: একটি অ্যারে, যেখানে বিভিন্ন অপারেশন, অপার্যান্ড এবং প্রত্যাশিত ফলাফল রয়েছে।
  • forEach(): এই অ্যারের উপর ভিত্তি করে ডায়নামিকভাবে টেস্ট তৈরি করা হচ্ছে।

JasmineJS এ Dynamic Test Generation এর সুবিধা

  1. কম কোড: একই ধরনের টেস্টগুলো একাধিক ইনপুটের জন্য কম কোডে লেখা সম্ভব।
  2. সামঞ্জস্য: বিভিন্ন ধরনের ইনপুটের জন্য এক ধরনের টেস্ট কেস লিখলে, তা আরও সমন্বিত এবং সুসংগত থাকে।
  3. সহজ রক্ষণাবেক্ষণ: একটি সাধারণ ফাংশনালিটি পরীক্ষা করতে একাধিক টেস্ট কেস ব্যবহার করা হলে কোড পুনঃব্যবহারযোগ্য এবং রক্ষণাবেক্ষণে সহজ হয়।

সারাংশ

  • Dynamic Test Generation দ্বারা আপনি একাধিক ইনপুট বা শর্তের জন্য একই ধরনের টেস্ট কেস তৈরি করতে পারেন।
  • JasmineJS এ forEach() বা অন্য যেকোনো ফাংশন ব্যবহার করে ইনপুট ডেটার উপর ভিত্তি করে ডায়নামিক টেস্ট কেস তৈরি করা সম্ভব।
  • এটি পুনঃব্যবহারযোগ্যতা, স্কেলেবিলিটি এবং অটোমেশন বৃদ্ধিতে সহায়তা করে, যা বড় প্রজেক্টে কার্যকরী।
  • কম কোড এবং সহজ রক্ষণাবেক্ষণ এর মাধ্যমে টেস্টিং প্রক্রিয়াটি আরো কার্যকরী হয়ে ওঠে।
Content added By

Complex Asynchronous Function টেস্ট করা

226

JasmineJS এ complex asynchronous functions (জটিল অ্যাসিঙ্ক্রোনাস ফাংশন) টেস্ট করা একটু চ্যালেঞ্জিং হতে পারে, কারণ এতে একাধিক asynchronous অপারেশন বা প্রতিক্রিয়া (callback, promise, setTimeout, ইত্যাদি) থাকতে পারে। তবে JasmineJS এর বিভিন্ন টুলস এবং কৌশল ব্যবহার করে আপনি এসব ফাংশনের টেস্টিং সহজেই করতে পারেন। এখানে আমরা কিছু সাধারণ কৌশল দেখবো যার মাধ্যমে আপনি জটিল অ্যাসিঙ্ক্রোনাস ফাংশন টেস্ট করতে পারবেন।


Complex Asynchronous Function কি?

Complex Asynchronous Function বলতে এমন ফাংশন বোঝানো হয়, যা একাধিক অ্যাসিঙ্ক্রোনাস অপারেশন বা কলব্যাকের সমন্বয়ে কাজ করে। উদাহরণস্বরূপ, কোনো API কল, সেটটাইমআউট (setTimeout), বা একাধিক প্রমিস (Promise) একত্রে ব্যবহার করে জটিল কার্যকলাপ সম্পন্ন হতে পারে।

যেহেতু JasmineJS অ্যাসিঙ্ক্রোনাস টেস্টিংয়ের জন্য done(), async/await, এবং promise সমর্থন করে, এইসব টুল ব্যবহার করে আমরা জটিল অ্যাসিঙ্ক্রোনাস ফাংশন সহজে টেস্ট করতে পারি।


Complex Asynchronous Function এর উদাহরণ

ধরা যাক, আমাদের একটি অ্যাসিঙ্ক্রোনাস ফাংশন আছে, যা প্রথমে একটি API কল করে, তারপর কিছু সময় পর একটি প্রক্রিয়া সম্পন্ন করে, এবং শেষে একটি callback ফাংশন কল করে।

function fetchDataAndProcess(callback) {
  setTimeout(function() {
    // প্রথমে কিছু ডেটা ফেচ করা হচ্ছে (এটা আসলে অ্যাসিঙ্ক্রোনাস হতে পারে)
    const data = { id: 1, name: 'John Doe' };
    
    // এরপর কিছু প্রসেসিং
    const processedData = { ...data, status: 'Processed' };

    // অবশেষে callback ফাংশন কল করা হচ্ছে
    callback(processedData);
  }, 1000);
}

এটি একটি complex asynchronous function, যেখানে একটি setTimeout দ্বারা একটি অ্যাসিঙ্ক্রোনাস কলব্যাক প্রক্রিয়া ব্যবহৃত হয়েছে।


JasmineJS তে Complex Asynchronous Function টেস্ট করা

জটিল অ্যাসিঙ্ক্রোনাস ফাংশন টেস্ট করতে, আপনি JasmineJS এর done() বা async/await ব্যবহার করতে পারেন। নিচে দুটি কৌশল দেখানো হলো:


done() Callback ব্যবহার করে টেস্ট

JasmineJS এ done() কলব্যাক ব্যবহার করে অ্যাসিঙ্ক্রোনাস কোডের শেষ হওয়া নিশ্চিত করা হয়। এটি সাধারণত ব্যবহার করা হয় যখন অ্যাসিঙ্ক্রোনাস কাজের ফলাফল পেতে কিছু সময় প্রয়োজন।

উদাহরণ: done() Callback ব্যবহার করে টেস্ট

describe("Complex Asynchronous Function", function() {
  it("should process data after fetching", function(done) {
    function callback(result) {
      expect(result.status).toBe("Processed");
      done();  // done() কল করা হয়েছে যাতে Jasmine জানে টেস্ট শেষ হয়েছে
    }

    fetchDataAndProcess(callback);  // অ্যাসিঙ্ক্রোনাস ফাংশন কল
  });
});

এখানে:

  • done() কল করা হচ্ছে ফাংশনের অ্যাসিঙ্ক্রোনাস কাজ শেষ হওয়ার পর।
  • JasmineJS অপেক্ষা করবে যতক্ষণ না done() কল করা হয়, তারপর টেস্টটি সম্পন্ন হবে।

async/await ব্যবহার করে টেস্ট

যেহেতু Promises অ্যাসিঙ্ক্রোনাস কোডের জন্য একটি সাধারণ পদ্ধতি, আপনি async এবং await ব্যবহার করে প্রমিস ভিত্তিক অ্যাসিঙ্ক্রোনাস কোডের টেস্ট করতে পারেন। JasmineJS async/await এর সঙ্গে কাজ করে, যাতে কোডটি আরো পরিষ্কার এবং সহজ হয়।

উদাহরণ: async/await ব্যবহার করে টেস্ট

describe("Complex Asynchronous Function", function() {
  it("should process data after fetching", async function() {
    const result = await new Promise((resolve, reject) => {
      fetchDataAndProcess(resolve);  // প্রমিসের মাধ্যমে অ্যাসিঙ্ক্রোনাস কল
    });

    expect(result.status).toBe("Processed");
  });
});

এখানে:

  • async: it() ব্লকটি অ্যাসিঙ্ক্রোনাস ফাংশন হিসেবে চিহ্নিত করা হয়েছে।
  • await: প্রমিসটির ফলাফল পাওয়ার জন্য await ব্যবহার করা হয়েছে।

এই পদ্ধতিতে, অ্যাসিঙ্ক্রোনাস ফাংশনের ফলাফল পাওয়ার জন্য কোনো done() কলব্যাকের প্রয়োজন নেই, কারণ await ফাংশনটি স্বয়ংক্রিয়ভাবে অপেক্ষা করবে প্রমিসের ফলাফলের জন্য।


Multiple Asynchronous Operations টেস্ট করা

কখনও কখনও আমাদের একাধিক অ্যাসিঙ্ক্রোনাস অপারেশন থাকতে পারে, যা একে অপরের উপর নির্ভরশীল। এই ক্ষেত্রে, আপনাকে নিশ্চিত করতে হবে যে সমস্ত অপারেশন সঠিকভাবে সম্পন্ন হয়েছে এবং ফলাফলগুলি একসঙ্গে যাচাই করা হবে।

উদাহরণ: একাধিক অ্যাসিঙ্ক্রোনাস অপারেশন টেস্ট করা

describe("Multiple Asynchronous Operations", function() {
  it("should process all data correctly", async function() {
    const result1 = await new Promise((resolve) => {
      setTimeout(() => resolve("Data 1 processed"), 1000);
    });
    const result2 = await new Promise((resolve) => {
      setTimeout(() => resolve("Data 2 processed"), 1500);
    });

    expect(result1).toBe("Data 1 processed");
    expect(result2).toBe("Data 2 processed");
  });
});

এখানে:

  • দুইটি আলাদা অ্যাসিঙ্ক্রোনাস প্রমিসকে await ব্যবহার করে সিকোয়েন্সিয়ালি টেস্ট করা হয়েছে।
  • JasmineJS নিজে থেকে সব অ্যাসিঙ্ক্রোনাস অপারেশন সম্পন্ন হওয়ার পর টেস্টের ফলাফল যাচাই করবে।

Promise.all() ব্যবহার করে একাধিক অ্যাসিঙ্ক্রোনাস অপারেশন টেস্ট করা

যদি একাধিক অ্যাসিঙ্ক্রোনাস অপারেশন একসঙ্গে সম্পন্ন হওয়ার পরে তাদের ফলাফল পরীক্ষা করতে চান, তবে Promise.all() ব্যবহার করতে পারেন।

উদাহরণ: Promise.all() দিয়ে একাধিক অ্যাসিঙ্ক্রোনাস অপারেশন টেস্ট

describe("Parallel Asynchronous Operations", function() {
  it("should process all data in parallel", async function() {
    const [result1, result2] = await Promise.all([
      new Promise((resolve) => setTimeout(() => resolve("Data 1 processed"), 1000)),
      new Promise((resolve) => setTimeout(() => resolve("Data 2 processed"), 500))
    ]);

    expect(result1).toBe("Data 1 processed");
    expect(result2).toBe("Data 2 processed");
  });
});

এখানে:

  • Promise.all(): দুটি আলাদা অ্যাসিঙ্ক্রোনাস অপারেশন একসঙ্গে চলতে থাকে, এবং সেগুলির ফলাফল পাওয়ার পর await করা হয়।
  • একাধিক অ্যাসিঙ্ক্রোনাস অপারেশন সম্পন্ন হওয়ার পর তাদের ফলাফল যাচাই করা হয়।

সারাংশ

  • Complex Asynchronous Functions টেস্ট করার জন্য JasmineJS এ done() বা async/await ব্যবহার করা যায়।
  • done() কলব্যাক অ্যাসিঙ্ক্রোনাস ফাংশনের শেষ হওয়ার পর টেস্ট সম্পন্ন করতে সাহায্য করে।
  • async/await পদ্ধতি প্রমিস ভিত্তিক অ্যাসিঙ্ক্রোনাস ফাংশন টেস্ট করার জন্য একটি আধুনিক এবং সহজ পদ্ধতি।
  • একাধিক অ্যাসিঙ্ক্রোনাস অপারেশন টেস্ট করার জন্য Promise.all() ব্যবহার করা যেতে পারে, যা অপারেশনগুলির সমান্তরালে কার্যকরী ফলাফল প্রাপ্তি নিশ্চিত করে।

JasmineJS এর এই টেস্টিং কৌশলগুলি আপনাকে জটিল অ্যাসিঙ্ক্রোনাস ফাংশন সহজভাবে পরীক্ষা করতে সহায়তা করবে।

Content added By

Advanced Spy Techniques

297

JasmineJS এ Spies (স্পাই) এমন একটি শক্তিশালী ফিচার যা আপনাকে ফাংশনের আচরণ ট্র্যাক করতে, আর্গুমেন্ট যাচাই করতে এবং রিটার্ন ভ্যালু বা ত্রুটি (error) পরীক্ষা করতে সহায়তা করে। স্পাই ব্যবহার করে আপনি আপনার কোডের কোনো ফাংশনকে "mock" বা "stub" করতে পারেন, যা টেস্ট করার জন্য বিশেষভাবে তৈরি করা হয়। এগুলো কাস্টম লজিকের মাধ্যমে টেস্ট চলাকালীন কোডের নির্দিষ্ট অংশ পরীক্ষা করতে ব্যবহৃত হয়।

এখানে আমরা Advanced Spy Techniques নিয়ে আলোচনা করব, যেগুলি আপনাকে আরও কার্যকরভাবে Jasmine এর স্পাই ফিচার ব্যবহার করতে সহায়তা করবে।


স্পাই-এর মৌলিক ধারণা

JasmineJS এ spyOn() মেথড ব্যবহার করে একটি ফাংশন স্পাই করা হয়। স্পাই একে অপরের কার্যকারিতা পরিবর্তন না করে, কেবলমাত্র ফাংশনটি ট্র্যাক করে। এটি আর্গুমেন্ট এবং রিটার্ন ভ্যালু সংক্রান্ত তথ্যও সংগ্রহ করে।

spyOn(object, 'methodName');

এখানে:

  • object: যেখানে ফাংশনটি অবস্থিত।
  • methodName: যেই মেথড/ফাংশনটি আপনি স্পাই করতে চান।

স্পাই সাধারণত তিনটি প্রধান কাজ করে:

  1. আর্গুমেন্টের মান ট্র্যাক করে।
  2. রিটার্ন ভ্যালু বা ফলাফল রেকর্ড করে।
  3. ফাংশনটির কল ট্র্যাক করে।

Advanced Spy Techniques

১. Spying on a Method and Checking Call Counts

Jasmine এর স্পাই ফিচার ব্যবহার করে আপনি ফাংশনটির কতবার কল করা হয়েছে তা ট্র্যাক করতে পারেন। এটি বিশেষভাবে তখন দরকারী, যখন আপনি চান জানতে, একটি ফাংশন কতবার কার্যকরী হয়েছে।

describe("Spy on call count", function() {
  it("should track how many times the function is called", function() {
    const obj = {
      greet: function(name) {
        return `Hello, ${name}!`;
      }
    };

    spyOn(obj, 'greet');
    obj.greet("John");
    obj.greet("Jane");

    expect(obj.greet).toHaveBeenCalledTimes(2);
  });
});

এখানে:

  • toHaveBeenCalledTimes(2) যাচাই করছে যে greet() ফাংশনটি ২ বার কল করা হয়েছে।

২. Using and.callThrough() to Call the Original Function

যখন আপনি একটি ফাংশন স্পাই করেন, আপনি চাইলে আসল ফাংশনটির আচরণও রাখতে পারেন। and.callThrough() মেথড ব্যবহার করে স্পাই করা ফাংশনটির আসল কার্যকারিতা চালু রাখুন এবং ট্র্যাক করুন।

describe("Spy with callThrough", function() {
  it("should call the original function", function() {
    const obj = {
      greet: function(name) {
        return `Hello, ${name}!`;
      }
    };

    spyOn(obj, 'greet').and.callThrough();
    const result = obj.greet("John");

    expect(result).toBe("Hello, John!");
    expect(obj.greet).toHaveBeenCalled();
  });
});

এখানে:

  • and.callThrough() স্পাইটি আসল greet ফাংশনের কার্যকারিতা বজায় রেখেছে এবং টেস্ট কেসে আর্গুমেন্ট এবং রিটার্ন ভ্যালু ট্র্যাক করা হয়েছে।

৩. Using and.returnValue() to Return a Custom Value

যখন আপনি চান যে একটি স্পাই করা ফাংশন নির্দিষ্ট একটি রিটার্ন ভ্যালু প্রদান করুক, তখন and.returnValue() ব্যবহার করতে পারেন। এটি একটি কাস্টম রিটার্ন ভ্যালু দেয়, যেটি আসল ফাংশনটির রিটার্ন ভ্যালু পরিবর্তন করে।

describe("Spy with returnValue", function() {
  it("should return a custom value", function() {
    const obj = {
      greet: function(name) {
        return `Hello, ${name}!`;
      }
    };

    spyOn(obj, 'greet').and.returnValue("Hello, Guest!");
    const result = obj.greet("John");

    expect(result).toBe("Hello, Guest!");
  });
});

এখানে:

  • and.returnValue("Hello, Guest!") স্পাই করা greet ফাংশনটি "Hello, Guest!" রিটার্ন করবে, যা আসল রিটার্ন ভ্যালুকে ওভাররাইড করে।

৪. Using and.callFake() for Custom Function Behavior

and.callFake() ব্যবহার করে আপনি স্পাই করা ফাংশনের জন্য একটি কাস্টম ফাংশন তৈরি করতে পারেন, যা মূল ফাংশনের আচরণ সম্পূর্ণরূপে পরিবর্তন করে। এটি তখন দরকারী, যখন আপনি স্পাই করা ফাংশনের জন্য একটি সম্পূর্ণ ভিন্ন কার্যকারিতা প্রয়োগ করতে চান।

describe("Spy with callFake", function() {
  it("should use a custom implementation", function() {
    const obj = {
      greet: function(name) {
        return `Hello, ${name}!`;
      }
    };

    spyOn(obj, 'greet').and.callFake(function(name) {
      return `Greetings, ${name}!`;
    });

    const result = obj.greet("John");

    expect(result).toBe("Greetings, John!");
  });
});

এখানে:

  • and.callFake() কাস্টম ফাংশন ব্যবহার করা হচ্ছে, যা আসল greet ফাংশনটির কার্যকারিতা সম্পূর্ণরূপে প্রতিস্থাপন করছে।

৫. Using and.throwError() to Simulate an Error

and.throwError() ব্যবহার করে আপনি স্পাই করা ফাংশনের জন্য একটি কাস্টম ত্রুটি (error) সিমুলেট করতে পারেন, যা টেস্টে ত্রুটি সৃষ্টির পরিস্থিতি যাচাই করতে সহায়ক।

describe("Spy with throwError", function() {
  it("should throw an error", function() {
    const obj = {
      greet: function(name) {
        if (!name) {
          throw new Error("Name is required!");
        }
        return `Hello, ${name}!`;
      }
    };

    spyOn(obj, 'greet').and.throwError("Name is required!");

    expect(function() { obj.greet(); }).toThrowError("Name is required!");
  });
});

এখানে:

  • and.throwError() স্পাই করা greet ফাংশনটিকে একটি ত্রুটি ছুঁড়তে বাধ্য করছে যখন এটি কোনো আর্গুমেন্ট ছাড়া কল করা হয়।

৬. Spy on Methods with Multiple Arguments

আপনি স্পাই করা ফাংশনটির একাধিক আর্গুমেন্ট যাচাই করতে পারেন এবং তার সাথে সংশ্লিষ্ট আচরণ পরীক্ষা করতে পারেন।

describe("Spy with multiple arguments", function() {
  it("should track multiple arguments", function() {
    const obj = {
      multiply: function(a, b) {
        return a * b;
      }
    };

    spyOn(obj, 'multiply');
    obj.multiply(2, 3);

    expect(obj.multiply).toHaveBeenCalledWith(2, 3);
  });
});

এখানে:

  • toHaveBeenCalledWith(2, 3) যাচাই করছে যে multiply ফাংশনটি 2 এবং 3 আর্গুমেন্ট নিয়ে কল হয়েছে কিনা।

সারাংশ

JasmineJS এর Advanced Spy Techniques আপনাকে আপনার কোডের বিভিন্ন দিক আরও গভীরভাবে পরীক্ষা করতে সহায়তা করে। spyOn(), and.callThrough(), and.returnValue(), and.callFake(), এবং and.throwError() এর মতো ফিচারগুলি ব্যবহার করে আপনি ফাংশনগুলির আচরণ ট্র্যাক করতে এবং কাস্টম রিটার্ন ভ্যালু, ত্রুটি সিমুলেশন, বা কাস্টম কার্যকারিতা প্রদান করতে পারেন। এগুলি আপনাকে আরও শক্তিশালী এবং নির্ভুল টেস্টিং করতে সক্ষম করে, যা কোডের ভুল বা অপ্রত্যাশিত আচরণ দ্রুত সনাক্ত করতে সাহায্য করে।

Content added By

Best Practices for Writing Maintainable Tests

192

Maintainable tests মানে এমন টেস্টগুলো যা সহজে পড়া যায়, বোঝা যায় এবং ভবিষ্যতে পরিবর্তন বা আপডেট করার সময় কম প্রচেষ্টা লাগে। JasmineJS ব্যবহার করে maintainable tests লেখা সঠিক টেস্টিং প্রক্রিয়া গড়ে তুলতে সহায়ক হতে পারে। নিচে কিছু best practices আলোচনা করা হলো, যা আপনাকে সহজ এবং সুসংগঠিত টেস্টিং কোড লিখতে সাহায্য করবে।


১. স্পষ্ট এবং বোধগম্য নামকরণ

আপনার টেস্ট কেসের নাম যেন স্পষ্টভাবে বর্ণনা করে টেস্টটি কী চেক করছে, তা নিশ্চিত করুন। সাধারণভাবে, describe এবং it ব্লকগুলো ব্যবহারকারীর আচরণ বা কোডের কার্যকারিতা বর্ণনা করবে।

ভাল উদাহরণ:

describe("User Registration", function() {
  it("should show an error message for missing fields", function() {
    // টেস্ট কোড
  });

  it("should successfully register a user with valid details", function() {
    // টেস্ট কোড
  });
});

খারাপ উদাহরণ:

describe("Registration", function() {
  it("should do something", function() {
    // টেস্ট কোড
  });
});

স্পষ্ট নামকরণ সাহায্য করবে পরবর্তীতে অন্য ডেভেলপার বা টেস্টার সহজে বুঝতে যাতে পারে যে, টেস্টটি কোন সিস্টেমের আচরণ পরীক্ষা করছে।


২. একটি টেস্টে একক দায়িত্ব রাখা

একটি টেস্টে একাধিক জিনিস পরীক্ষা না করে শুধুমাত্র একটি নির্দিষ্ট আচরণ বা ফিচার পরীক্ষা করুন। এতে টেস্টগুলো ছোট এবং সহজে রক্ষণাবেক্ষণযোগ্য হবে।

ভাল উদাহরণ:

describe("Login Functionality", function() {
  it("should log in a user with valid credentials", function() {
    // কোড
  });

  it("should show an error message for invalid credentials", function() {
    // কোড
  });
});

খারাপ উদাহরণ:

describe("Login Functionality", function() {
  it("should log in the user with valid credentials and then redirect to the dashboard", function() {
    // কোড
  });
});

একটি টেস্টে একাধিক আচরণ পরীক্ষা করা, পরবর্তীতে যখন কোনো একটি অংশ পরিবর্তন হবে, তখন ডিবাগ করা আরও কঠিন হতে পারে।


৩. Reusable Setup ব্যবহার করা (beforeEach এবং afterEach)

আপনি যদি একাধিক টেস্টে একই ধরনের সেটআপ বা ক্লিনআপ করতে চান, তবে beforeEach() এবং afterEach() ফাংশন ব্যবহার করতে পারেন। এটি কোড পুনঃব্যবহারযোগ্য এবং আরও পরিষ্কার করবে।

ভাল উদাহরণ:

describe("Shopping Cart", function() {
  let cart;

  beforeEach(function() {
    cart = new ShoppingCart();
  });

  it("should add an item to the cart", function() {
    cart.addItem("Laptop");
    expect(cart.items.length).toBe(1);
  });

  it("should remove an item from the cart", function() {
    cart.addItem("Laptop");
    cart.removeItem("Laptop");
    expect(cart.items.length).toBe(0);
  });
});

এখানে beforeEach() ফাংশনটি প্রতিটি টেস্টের আগে একই রকম সেটআপ নিশ্চিত করে, যাতে কোড ডুপ্লিকেশন এড়ানো যায়।


৪. টেস্টের জন্য স্টাব এবং স্পাই ব্যবহার

JasmineJS spies ব্যবহার করে, আপনি ফাংশনের কার্যকারিতা পরীক্ষা করতে পারেন বা অন্যান্য মডিউলের আচরণ সিমুলেট করতে পারেন। তবে, stubbing বা spying করার সময় টেস্টটি যেন অনেক জটিল বা অপ্রয়োজনীয় না হয়ে যায়, তা নিশ্চিত করতে হবে।

ভাল উদাহরণ (Spying):

describe("User Login", function() {
  it("should call the login API with correct parameters", function() {
    const loginSpy = spyOn(api, 'login');
    user.login('username', 'password');
    expect(loginSpy).toHaveBeenCalledWith('username', 'password');
  });
});

খারাপ উদাহরণ (Spying):

describe("User Login", function() {
  it("should call the login API and show loading spinner", function() {
    const loginSpy = spyOn(api, 'login');
    user.login('username', 'password');
    // এখানে অনেক জটিল ফাংশনালিটি পরীক্ষা করা হচ্ছে যা একাধিক দায়িত্ব পালন করছে
    expect(loginSpy).toHaveBeenCalledWith('username', 'password');
  });
});

টেস্টে অতিরিক্ত দায়িত্ব নেয়া থেকে বিরত থাকুন। শুধু প্রয়োজনীয় ফাংশনালিটি পরীক্ষা করুন।


৫. পরিবর্তনশীল ডেটার জন্য mocks এবং fixtures ব্যবহার

যখন আপনার টেস্টে ডেটা বা পরিবেশের নির্ভরতা থাকে, তখন mocks বা fixtures ব্যবহার করে ডেটা সিমুলেট করুন। এতে আপনার টেস্ট চলাকালীন প্রকৃত পরিবেশের উপর নির্ভরশীলতা কমে যাবে এবং টেস্টগুলো আরও স্থিতিশীল হবে।

ভাল উদাহরণ (Mocking):

describe("User Profile", function() {
  it("should load user data from API", function() {
    const mockUserData = { name: "John", age: 30 };
    spyOn(api, 'getUserData').and.returnValue(mockUserData);
    
    const user = new UserProfile();
    user.loadData();
    
    expect(user.name).toBe("John");
    expect(user.age).toBe(30);
  });
});

এখানে, getUserData API কলের পরিবর্তে একটি mock ব্যবহার করা হয়েছে, যাতে কোনো আসল API কলের প্রয়োজন না পড়ে এবং টেস্ট দ্রুত চলে।


৬. টেস্টের জন্য যথাযথ Assertions ব্যবহার করা

JasmineJS এর matchers (যেমন toBe(), toEqual(), toContain(), toBeTruthy()) ব্যবহার করে সঠিকভাবে assertions লিখুন। এটি টেস্টের ফলাফলকে আরও নির্ভুল এবং স্পষ্ট করে তুলবে।

ভাল উদাহরণ:

it("should return the correct sum", function() {
  const sum = add(2, 3);
  expect(sum).toBe(5); // সঠিকভাবে assertion
});

খারাপ উদাহরণ:

it("should return the correct sum", function() {
  const sum = add(2, 3);
  expect(sum).toBeGreaterThan(4); // এই assertion থেকে সঠিক ফলাফল প্রাপ্তি সন্দেহজনক
});

৭. টেস্টে ডিজাইন প্যাটার্ন ব্যবহার করুন

আপনি Page Object Model (POM) বা অন্যান্য ডিজাইন প্যাটার্ন ব্যবহার করে টেস্টকে আরও রক্ষণাবেক্ষণযোগ্য ও স্কেলেবল করতে পারেন। এটি বড় অ্যাপ্লিকেশনের জন্য বিশেষভাবে কার্যকর।

ভাল উদাহরণ (Page Object Model):

class LoginPage {
  constructor() {
    this.usernameField = document.getElementById('username');
    this.passwordField = document.getElementById('password');
    this.loginButton = document.getElementById('loginButton');
  }

  login(username, password) {
    this.usernameField.value = username;
    this.passwordField.value = password;
    this.loginButton.click();
  }
}

describe("Login Functionality", function() {
  let loginPage;

  beforeEach(function() {
    loginPage = new LoginPage();
  });

  it("should log in successfully with valid credentials", function() {
    loginPage.login("validUser", "validPassword");
    expect(window.location.href).toBe("https://example.com/dashboard");
  });
});

এখানে LoginPage ক্লাসটি পুনঃব্যবহারযোগ্য এবং পরীক্ষামূলক। এটি টেস্টের অন্য অংশের থেকে UI লগইন ফাংশনালিটি আলাদা রাখে।


৮. অতিরিক্ত dependencies এড়ানো

JasmineJS টেস্টে dependencies বা বাইরের লাইব্রেরি ব্যবহারের সময় সতর্ক থাকুন। যদি সম্ভব হয়, শুধুমাত্র মূল কোড বা কার্যকারিতা পরীক্ষা করুন এবং বাইরের লাইব্রেরি ব্যবহার এড়িয়ে চলুন।


সারাংশ

JasmineJS-এ maintainable টেস্ট লিখতে কিছু সেরা প্র্যাকটিস অনুসরণ করা উচিত। স্পষ্ট নামকরণ, ছোট এবং ফোকাসড টেস্ট লেখা, reusable setup ব্যবহার, এবং mocks/spies ব্যবহার করা কিছু গুরুত্বপূর্ণ অভ্যাস যা টেস্টগুলোকে আরও পাঠযোগ্য এবং রক্ষণাবেক্ষণযোগ্য করে তোলে। এই প্র্যাকটিসগুলো অনুসরণ করলে আপনার টেস্টগুলো সহজে পরিচালনা করা যাবে এবং ভবিষ্যতে যখন কোড পরিবর্তন হবে, তখন টেস্টগুলো আপডেট বা ঠিক করা সহজ হবে।

Content added By
Promotion
NEW SATT AI এখন আপনাকে সাহায্য করতে পারে।

Are you sure to start over?

Loading...